//
//  This copyrighted © code is written for and is part of the book
//  Smartphone-Based Real-Time Digital Signal Processing
//
package com.dsp.spectrogram;

import java.util.concurrent.atomic.AtomicBoolean;

import android.media.AudioFormat;
import android.media.MediaRecorder;

public class Settings {
	
	public static final int FORMAT = AudioFormat.ENCODING_PCM_16BIT;
	public static final int SOURCE = MediaRecorder.AudioSource.MIC;
	public static final WaveFrame STOP = new WaveFrame(new short[] {1,2,4,8});
	public static int Fs = 8000;
	public static int overlapSize = 64;
	public static int stepSize = 64;
	public static int windowSize = 128;
	public static int fftPoints = 128;
	public static int graphPoints = fftPoints/2+1;
	public static int windowFunction = 0;
	public static float binStep = 0.0625f;
	public static boolean playback = false;
	public static boolean changed = false;
	public static AtomicBoolean graphReady = new AtomicBoolean(false);
	public static int debugOutput = 0;
	public static int debugLevel = 0;
	private static Monitor main;
	private static DataListener graphListener;
	
	//UI update interval
	public static int secondConstant = Fs/stepSize;
	
	//supported sampling rates
	public static CharSequence[] samplingRates = {"8000 Hz"};
	public static CharSequence[] samplingRateValues = {"8000"};
	
	public static String[] debugOutputNames = {"Default"};
	public static String[] debugLevels = {"Default"};
	public static String[] windowOptions = {"Default"};
	
	public static void setCallbackInterface(Monitor uiInterface) {
		main = uiInterface;
	}
	
	public static Monitor getCallbackInterface() {
		return main;
	}
	
	public static void graphListener(DataListener listener) {
		graphListener = listener;
	}
	
	public static DataListener getDataListener(){
		return graphListener;
	}
	
	public static boolean setFFTPoints(int points){
		int pow2Size = Utilities.nextPower2(points);
		if (pow2Size >= windowSize) {
			fftPoints = pow2Size;
			graphPoints = pow2Size/2+1;
			binStep = (Fs*0.001f)/pow2Size;
			changed = true;
			return true;
		}
		return false;
	}	
	
	public static boolean setOverlapSize(int overlapsize){
		if (overlapsize >= 0 && overlapsize < windowSize) {
			int stepsize = windowSize - overlapsize;
			if (stepSize != stepsize) {
				stepSize = stepsize;
				overlapSize = overlapsize;
				secondConstant = Fs/stepsize;
				changed = true;
				return true;
			}
		}
		return false;
	}
	
	public static boolean setWindowSize(int windowsize){
		if(windowsize > 0) {
			if (windowSize != windowsize && windowsize > overlapSize) {
				windowSize = windowsize;
				stepSize = windowsize-overlapSize;
				if(fftPoints < Utilities.nextPower2(windowSize)){
					setFFTPoints(windowSize);
				}
				changed = true;
				return true;
			}
		}
		return false;
	}
	
	public static boolean setSamplingFrequency(int freq){
		if(Fs != freq){
			Fs = freq;
			secondConstant = Fs/stepSize;
			binStep = (Fs*0.001f)/fftPoints;
			changed = true;
			return true;
		}
		return false;
	}
	
	public static boolean setPlayback(boolean flag){
		if(playback != flag){
			playback = flag;
			changed = true;
			return true;
		}
		return false;
	}
	
	public static boolean setWindowFunction(int option){
		if(option < 0 || option > windowOptions.length){
			return false;
		} else if (windowFunction != option){
			windowFunction = option;
			changed = true;
			return true;
		}
		return false;
	}
	
	public static String getWindowFunction(){
		return windowOptions[windowFunction];
	}
	
	public static boolean setDebugLevel(int level){
		if(level < 0 || level > debugLevels.length){
			return false;
		} else if (debugLevel != level){
			debugLevel = level;
			changed = true;
			return true;
		}
		return false;
	}
	
	public static String getDebugLevel(){
		return debugLevels[debugLevel];
	}
		
	public static boolean setDebugOutput(int output){
		if(output < 0 || output > debugOutputNames.length) {
			return false;
		} else if(debugOutput != output){
			debugOutput = output;
			changed = true;
			return true;
		}
		return false;
	}
	
	public static String getDebugOutput(){
		return debugOutputNames[debugOutput];
	}
	
	public static void setRates(CharSequence[] rates){
		samplingRates = rates;
	}
	
	public static void setRateValues(CharSequence[] rateValues){
		samplingRateValues = rateValues;
	}

	public static int blockSize = 256;
	public static boolean output = false;

	public static int D = 0;
	public static float a = 1.0f;

	public static boolean setDelay(int time){
		if(D != time){
			D = time;
			changed = true;
			return true;
		}
		return false;
	}

	public static boolean setAlpha(float value){
		if(a != value){
			a = value;
			changed = true;
			return true;
		}
		return false;
	}

	public static boolean setBlockSize(int size){
		int mult4Size = 4;
		while (mult4Size < size) {
			mult4Size = mult4Size << 1;
		}
		if(size != 0 && blockSize != mult4Size){
			blockSize = mult4Size;
			secondConstant = Fs/mult4Size;
			changed = true;
			return true;
		}
		return false;
	}

	public static boolean setOutput(int stream){
		if((stream == 1) && (output != true)) { //original signal
			output = true;
			changed = playback;
			return playback;
		} else if((stream == 2) && (output != false)) { //filtered signal
			output = false;
			changed = playback;
			return playback;
		}
		return false;
	}

	public static String getOutput(){
		if(playback == false){
			return "None";
		} else if (output == true){
			return "Original";
		} else {
			return "Filtered";
		}
	}

	public static String getDebug(){
		if(debugLevel == 4){
			return "None";
		} else if (debugLevel == 3){
			return "PCM";
		} else if(debugLevel == 2){
			return "Text";
		} else if(debugLevel == 1){
			return("All");
		}
		return "How could you let this happen?";
	}
}
